package ua.dp.mzav.train.tm.model;

import java.io.Serializable;

/**
 * This class represents a Domain Model entity according to NFR2.1
 *
 * Employee - is a subject of accounting in the System.
 *
 * @note This class provides non-modifiable only interface for the entity.
 *       That's why the class is abstract.
 * @note Empty string for title and names has special meaning - the corresponded part of name is not used.
 *       null means it is not defined, i.e. unknown yet.
 * 
 * The most probably the class is a subject of subclassing the bigest part
 * of data into a superclass like Person, but the Requirements do not declare
 * another Entity where it could be used also.
 */
public abstract class EmployeeReadable implements Serializable
{
   private static final long serialVersionUID = 1L;
    
    
   /// @serial String with title or null if it is not defined.
   protected String title;

   /// @serial String with first name or null if it is not defined.
   protected String firstName;
    
   /// @serial String with midle name or null if it is not defined.
   protected String middleName;
    
   /// @serial String with last name or null if it is not defined.
   protected String lastName;
    
   /// @serial Reference to the Manager or null. Can not refer itself.
   protected Employee manager;
   
   /// @serial Reference to the Supervisor or null. Can not refer itself.
   protected Employee supervisor;

   /// @serial 0 means the key is not defined yet - for newly created objects.
   int id;
    
   /// @name Person data.
   ///@{
    
    /** Returns Title of the Employee, for instance Mr. or Ms.
     * 
     * @return Title of the Employee.
     * @retval "" Title is not used for Employee.
     * @retval null Title is not defined (unknown) for Employee.
     * @see Employee#setTitle(String)
     */
    public final String getTitle()
    {
        return title;
    }

    /** Returns First Name of the Employee.
     * 
     * @return First Name of the Employee.
     * @retval "" First Name is not used for Employee.
     * @retval null First Name is not defined (unknown) for Employee.
     * @see Employee#getFirstName()
     */
    public final String getFirstName()
    {
        return firstName;
    }

    /** Returns Middle Name of the Employee.
     * 
     * @return Middle Name of the Employee.
     * @retval "" Middle Name is not used for Employee.
     * @retval null Middle Name is not defined (unknown) for Employee.
     * @see Employee#setMiddleName(String)
     */
    public final String getMiddleName()
    {
        return middleName;
    }

    /** Returns Last Name of the Employee.
     * 
     * @return Last Name of the Employee.
     * @retval "" Last Name is not used for Employee.
     * @retval null Last Name is not defined (unknown) for Employee.
     * @see Employee#setLastName(String)
     */
    public final String getLastName()
    {
        return lastName;
    }
    
    /**
     * Full name of the Employee in format "{title} {first name} {middle name}
     * {last name}".
     * 
     * Not all parts of name can be defined - in this case they are ignored 
     * and no aditional spaces are added.
     *
     * @return Full name in the specified format.
     */
    public final String getFullName()
    {
        final StringBuilder sb = new StringBuilder();
        appendName(sb, title);
        appendName(sb, firstName);
        appendName(sb, middleName);
        appendName(sb, lastName);
        return sb.toString();
    }

    private static void appendName(final StringBuilder aBuilder, final String aString)
    {
        if (aString != null && !aString.isEmpty())
        {
            if (aBuilder.length() > 0)
            {
                aBuilder.append(' ');
            }
            aBuilder.append(aString);
        }
    }

    ///@}

    
    /** Supervisor of the employer - according to NFR1.4
     * 
     * @return Supervisor. Can not refer itself. Can not refer Manager.
     * @retval null If Supervisor has not been specified explicitly.
     */
    public abstract EmployeeReadable getSupervisor();

    /** Manager of the employer - according to NFR1.2
     * 
     * @return Manager. Can not refer itself.
     * @retval null If the Employee is Top-Manager NFR2.3
     */
    public abstract EmployeeReadable getManager();



   /** Provides identity of Employers.
     * 
     * @return true/false
     * @note Name is not used for identifying Employers - 
     *       a surrogate key is used instead.
     */
    @Override
    public final boolean equals(Object anOther)
    {
        boolean retVal = false;
        if (anOther instanceof Employee)
        {
            final Employee other = (Employee) anOther;
            retVal = (id == 0 || other.id == 0) ? (this == anOther) : (id == other.id);
        }
        return retVal;
    }

    /**
     * Utility for Emlpoyer identification - see EmployeeReadable#equals.
     *
     * @return true/false 
     * @note Name is not used for identifying Employers - 
     *       a surrogate key is used instead.
     */
    @Override
    public final int hashCode()
    {
        return id;
    }

    /*
     * @return EmployeeReadable#getFullName.
     */
    @Override
    public String toString()
    {
        return getFullName();
    }
}
